# -*- coding: UTF-8 -*-
import tkinter as tk
from tkinter import ttk
from Code.View.sc_base import NotInputError
from Code.View.sc_global import Global
from Code.View.sc_module import TitleFrame, WidgetTip, InfoText
from Code.View.Datamation.sc_provide import view_gate


class TimezoneWidgets(object):
    def __init__(self, master, width, height):
        self.frame = master
        self.width = width
        self.height = height
        self.row = 5
        self.column = 3
        self.subcmb_list = self.get_struct_array()   # 用来保存排列的combobox实例
        self.cmbval_list = self.get_struct_array()   # 用来保存各个combobox中显示的值
        self.label_list = self.get_struct_array()
        self.opts_dict = {}
        self.text_shower = None

    # ----------------------------------------------------------------#
    #                           必须要实现的方法                        #
    # ----------------------------------------------------------------#
    def pack_widgets(self):
        self.init_combox_data()
        self.create_grid()
        self.init_display()

    def get_plot_widgets(self):
        return []

    def update_widgets_values(self, ip, values):
        (which, value), = values[0].items()
        self.text_shower.insert_markdown("###### > {}\n{}\n".format(ip, value))

    def get_widgets_values(self, ip):
        not_set = self.exist_not_set_combox()
        if not_set:
            raise NotInputError("{} cant be NULL".format(not_set[0]))
        params_dict = [{},
                       {"Custom": self.options_combine()}
                       ]
        upload_dict = {ip: []}
        return params_dict, upload_dict

    def clear_widgets_values(self):
        self.text_shower.clear()

    #----------------------------------------------------------------#
    #                           业务逻辑代码                          #
    #----------------------------------------------------------------#
    def init_combox_data(self):
        self.cmbval_list[0][0] = self.get_zonearea_tup()
        self.cmbval_list[0][1] = self.get_month_tup()
        self.cmbval_list[0][2] = self.get_month_tup()
        self.cmbval_list[1][0] = ('YES', 'NO')
        self.cmbval_list[1][1] = self.get_month_day_tup()
        self.cmbval_list[1][2] = self.get_month_day_tup()
        self.cmbval_list[2][0] = ('DATE', 'WEEK')
        self.cmbval_list[2][1] = self.get_weekseq_tup()
        self.cmbval_list[2][2] = self.get_weekseq_tup()
        self.cmbval_list[3][0] = ('DATE', 'WEEK')
        self.cmbval_list[3][1] = self.get_week_tup()
        self.cmbval_list[3][2] = self.get_week_tup()
        self.cmbval_list[4][0] = self.get_offset_time_tup()
        self.cmbval_list[4][1] = self.get_day_hour_tup()
        self.cmbval_list[4][2] = self.get_min_second_tup()
        self.cmbval_list[4][3] = self.get_min_second_tup()
        self.cmbval_list[4][4] = self.get_day_hour_tup()
        self.cmbval_list[4][5] = self.get_min_second_tup()
        self.cmbval_list[4][6] = self.get_min_second_tup()

    def create_grid(self):
        bg_color = Global.G_DEFAULT_COLOR
        state_fm = tk.Frame(self.frame)
        state_fm.pack(fill='x', padx=5)
        title = view_gate.query_language_data('CURRENT', 'STATUS')
        self.text_shower = InfoText(TitleFrame(state_fm, self.width - 30, 300, title).master())
        opt_fm = tk.LabelFrame(self.frame, bg=bg_color, width=self.width)
        opt_fm.pack(fill='x', padx=5, pady=5)
        for x in range(self.row):
            for y in range(self.column):
                fm = tk.Frame(opt_fm, bg=bg_color, width=self.width/self.column-1, height=self.height/self.row-1)
                fm.grid(row=x, column=y, padx=2, sticky='e')
                # 两个时间的，需要特殊处理
                if x == self.row-1 and y in [self.column-2, self.column-1]:
                    lab = tk.Label(fm, bg=bg_color, text=self.get_labname(x, y), font=(Global.G_DEFAULT_FONT, 10))
                    lab.pack(side='left')
                    self.label_list[x][y] = lab
                    # 由于y在 x=row-1的时候，相对以前多加了两列，所以下次y要多加2才是正确的数组位置
                    tmp_y = y
                    if y == self.column-1:
                        tmp_y = y+2
                    subfm = tk.Frame(fm, bg=bg_color, width=self.width/self.column/2-1, height=self.height/self.row/2-1)
                    subfm.pack(side='right')
                    for i in range(3):
                        combox_var = tk.StringVar()
                        subcmb = ttk.Combobox(subfm, textvariable=combox_var, width=2)
                        subcmb["values"] = self.cmbval_list[x][tmp_y+i]
                        subcmb.current(0)
                        subcmb["state"] = "readonly"
                        subcmb.bind("<<ComboboxSelected>>", func=self.handler_adaptor(
                            self.choose_opt, cmb=subcmb, x=x, y=tmp_y+i))
                        subcmb.pack(side='left')
                        self.subcmb_list[x][tmp_y+i] = subcmb
                        if i != 2:
                            tk.Label(subfm, text=':').pack(side='left')
                else:
                    lab = tk.Label(fm, bg=bg_color, text=self.get_labname(x, y), font=(Global.G_DEFAULT_FONT, 10))
                    lab.pack(side='left')
                    self.label_list[x][y] = lab
                    combox_var = tk.StringVar()
                    cmb = ttk.Combobox(fm, textvariable=combox_var, width=14)
                    cmb["values"] = self.cmbval_list[x][y]
                    cmb.current(0)
                    cmb["state"] = "readonly"
                    cmb.bind("<<ComboboxSelected>>", func=self.handler_adaptor(self.choose_opt, cmb=cmb, x=x, y=y))
                    cmb.pack(side='right', padx=4)
                    # 子窗体中的combox存入二位数组
                    self.subcmb_list[x][y] = cmb

    def get_labname(self, x, y):
        return [['TimeZone\n时区', 'Start month\n开始月份', 'End month\n结束月份'],
                ['DaylightSave\n夏令时', 'Start date\n开始日期', 'End date\n结束日期'],
                ['StartType\n开始类型', 'Start week sequence\n开始星期序列', 'End week sequence\n结束星期序列'],
                ['EndType\n结束类型', 'Start week\n开始星期', 'End week\n结束星期'],
                ['AdjustMethod\n时间偏移量', 'Start time\n开始时间', 'End time\n结束时间']][x][y]

    def get_abbre_opts(self, x, y):
        return [['ZONET', 'SMONTH', 'EMONTH'],
                ['DST', 'SDAY', 'EDAY'],
                ['SMODE', 'SWSEQ', 'EWSEQ'],
                ['EMODE', 'SWEEK', 'EWEEK'],
                ['METHOD', 'STIMEH', 'STIMEM', 'STIMES', 'ETIMEH', 'ETIMEM', 'ETIMES']][x][y]

    def get_index_byname(self, name):
        """ 根据传入的option的name，返回所在二维列表中的位置 """
        namelist = [['ZONET', 'SMONTH', 'EMONTH'],
                    ['DST', 'SDAY', 'EDAY'],
                    ['SMODE', 'SWSEQ', 'EWSEQ'],
                    ['EMODE', 'SWEEK', 'EWEEK'],
                    ['METHOD', 'STIMEH', 'STIMEM', 'STIMES', 'ETIMEH', 'ETIMEM', 'ETIMES']]
        x = 0
        for sublist in namelist:
            x += 1
            y = 0
            for nm in sublist:
                y += 1
                if name == nm:
                    return [x-1, y-1]
        return []

    def exist_not_set_combox(self):
        """ 根据不同设置类型的key最小集，判断是否还有没有设置的combox """
        scene1 = ['ZONET', 'DST']
        scene2 = ['ZONET', 'DST', 'SMODE', 'SMONTH', 'SDAY', 'STIMES', 'STIMEM', 'STIMEH', 'EMODE', 'EMONTH',
                  'EDAY', 'ETIMES', 'ETIMEM', 'ETIMEH', 'METHOD']
        scene3 = ['ZONET', 'DST', 'SMODE', 'SMONTH', 'SDAY', 'STIMES', 'STIMEM', 'STIMEH', 'EMODE', 'EMONTH',
                  'EWSEQ', 'EWEEK', 'ETIMES', 'ETIMEM', 'ETIMEH', 'METHOD']
        scene4 = ['ZONET', 'DST', 'SMODE', 'SMONTH', 'SWSEQ', 'SWEEK', 'STIMES', 'STIMEM', 'STIMEH', 'EMODE',
                  'EMONTH', 'EDAY', 'ETIMES', 'ETIMEM', 'ETIMEH', 'METHOD']
        scene5 = ['ZONET', 'DST', 'SMODE', 'SMONTH', 'SWSEQ', 'SWEEK', 'STIMES', 'STIMEM', 'STIMEH', 'EMODE',
                  'EMONTH', 'EWSEQ', 'EWEEK', 'ETIMES', 'ETIMEM', 'ETIMEH', 'METHOD']
        if 'DST' not in self.opts_dict:
            return ['DST']
        elif 'ZONET' not in self.opts_dict:
            return ['ZONET']
        elif self.opts_dict['DST'] == 'NO':
            return []
        elif 'SMODE' not in self.opts_dict:
            return ['SMODE']
        elif 'EMODE' not in self.opts_dict:
            return ['EMODE']
        elif 'METHOD' not in self.opts_dict:
            return ['METHOD']
        tmplist = []
        if self.opts_dict['SMODE'] == 'DATE' and self.opts_dict['EMODE'] == 'DATE':
            tmplist = scene2
        elif self.opts_dict['SMODE'] == 'DATE' and self.opts_dict['EMODE'] == 'WEEK':
            tmplist = scene3
        elif self.opts_dict['SMODE'] == 'WEEK' and self.opts_dict['EMODE'] == 'DATE':
            tmplist = scene4
        elif self.opts_dict['SMODE'] == 'WEEK' and self.opts_dict['EMODE'] == 'WEEK':
            tmplist = scene5
        outlist = []
        for i in tmplist:
            if i not in self.opts_dict:
                if i in ['STIMES', 'STIMEH', 'STIMEM'] and 'STIME' in self.opts_dict:
                    continue
                if i in ['ETIMES', 'ETIMEH', 'ETIMEM'] and 'ETIME' in self.opts_dict:
                    continue
                outlist.append(i)
        return outlist

    def get_index_list(self, index=None):
        tmp_list = [[0, 0], [0, 1], [0, 2], [1, 0], [1, 1], [1, 2], [2, 0], [2, 1], [2, 2], [3, 0], [3, 1], [3, 2],
                    [4, 0], [4, 1], [4, 2], [4, 3], [4, 4], [4, 5], [4, 6]]
        if index:
            return tmp_list[index]
        return tmp_list

    def get_day_list(self, month):
        """
        根据月份返回天数
        夏令时不能设在闰年的2月29
        所以2分返回28天
        """
        month = int(month)
        if month == 2:
            return 28
        elif month in [4, 6, 9, 11]:
            return 30
        elif month in [1, 3, 5, 7, 8, 10, 12]:
            return 31
        else:
            return -1

    def get_struct_array(self):
        return [['', '', ''], ['', '', ''], ['', '', ''], ['', '', ''], ['', '', '', '', '', '', '']]

    def get_offset_time_tup(self, forfind=False):
        """ 获取夏令时偏移量的元组 """
        a = tuple(range(1, 121))
        b = tuple(range(-120, 0))
        tup = a + b
        if forfind:
            if forfind not in tup:
                return -1
            return tup.index(forfind)
        return tup

    def get_min_second_tup(self):
        """ 获取一小时的分钟或一分钟的秒数的元组 """
        return tuple(range(60))

    def get_day_hour_tup(self):
        """ 获取一天中的各个小时的元组 """
        return tuple(range(24))

    def get_month_day_tup(self):
        """ 获取一个月的天数的元组,最大的31天 """
        return tuple(range(1, 32))

    def get_month_tup(self, forfind=False):
        tup = ('一月(Jan)', '二月(Feb)', '三月(Mar)', '四月(Apr)', '五月(May)', '六月(Jun)',
               '七月(Jul)', '八月(Aug)', '九月(Sep)', '十月(Oct)', '十一月(Nov)', '十二月(Dec)')
        if forfind:
            if forfind not in tup:return -1
            # 加1,是因为返回的是月份数字
            return tup.index(forfind)+1
        return tup

    def get_zonearea_tup(self, forfind=False):
        tup = ('GMT+14:00', 'GMT+13:00', 'GMT+12:45', 'GMT+12:00', 'GMT+11:30', 'GMT+11:00', 'GMT+10:30', 'GMT+10:00',
               'GMT+09:30', 'GMT+09:00', 'GMT+08:45', 'GMT+08:00', 'GMT+07:00', 'GMT+06:30', 'GMT+06:00', 'GMT+05:30',
               'GMT+05:00', 'GMT+04:30', 'GMT+04:00', 'GMT+03:30', 'GMT+03:00', 'GMT+02:00', 'GMT+01:00', 'GMT+00:00',
               'GMT-01:00', 'GMT-02:00', 'GMT-03:00', 'GMT-03:30', 'GMT-04:00', 'GMT-04:30', 'GMT-05:00', 'GMT-06:00',
               'GMT-07:00', 'GMT-07:30', 'GMT-08:00', 'GMT-08:30', 'GMT-09:00', 'GMT-09:30', 'GMT-10:00', 'GMT-10:30',
               'GMT-11:00', 'GMT-12:00')
        if forfind:
            if forfind not in tup:
                return -1
            ''' 这里不加1，是因为这里跟数字没有关系，只是获取索引 '''
            return tup.index(forfind)
        return tup

    def get_weekseq_tup(self, forfind=False):
        tup = ('第一个(First)', '第二个(Second)', '第三个(Third)', '第四个(Fourth)', '最后一个(Last)')
        if forfind:
            if forfind not in tup:return -1
            return tup.index(forfind)+1
        return tup

    def get_week_tup(self, forfind=False):
        tup = ('星期一(Mon)', '星期二(Tues)', '星期三(Wed)', '星期四(Thur)', '星期五(Fri)', '星期六(Sat)', '星期日(Sun)')
        if forfind:
            if forfind not in tup:
                return -1
            return tup.index(forfind)+1
        return tup

    def handler_adaptor(self, fun,  **kwds):
        return lambda event, fun=fun, kwds=kwds: fun(event, **kwds)

    def check_limit_dependence(self, key, value):
        if key not in ['SDAY', 'EDAY', 'SMONTH', 'EMONTH']:
            return True
        if key == 'SDAY':
            if 'SMONTH' not in self.opts_dict:
                return True
            if int(value) < 28:
                return True
            month = int(self.opts_dict['SMONTH'])
            if month == 2 and int(value) > 28:
                WidgetTip.error('The date cannot be set to be greater than the 28th when Start-month is February.')
                self.reset_combox_list([[1, 1]])
                self.pop_opts_dict('SDAY')
                return False
            elif month in [4, 6, 9, 11] and int(value) > 30:
                WidgetTip.error('The date cannot be set to be greater than the 30th when Start-month is %s.' % month)
                self.reset_combox_list([[1, 1]])
                self.pop_opts_dict('SDAY')
                return False
        elif key == 'EDAY':
            if 'EMONTH' not in self.opts_dict:
                return True
            if int(value) < 28:
                return True
            month = int(self.opts_dict['EMONTH'])
            if month == 2 and int(value) > 28:
                WidgetTip.error('The date cannot be set to be greater than the 28th when End-month is February.')
                self.reset_combox_list([[1, 2]])
                self.pop_opts_dict('EDAY')
                return False
            elif month in [4, 6, 9, 11] and int(value) > 30:
                WidgetTip.error('The date cannot be set to be greater than the 30th when End-month is %s.' % month)
                self.reset_combox_list([[1, 2]])
                self.pop_opts_dict('EDAY')
                return False
        elif key == 'SMONTH':
            if 'SDAY' not in self.opts_dict:
                return True
            day = int(self.opts_dict['SDAY'])
            if int(value) == 2 and day > 28:
                WidgetTip.error('The date cannot be set to be greater than the 28th when Start-month is February.')
                self.reset_combox_list([[0, 1]])
                self.pop_opts_dict('SMONTH')
                return False
            elif int(value) in [4, 6, 9, 11] and day > 30:
                WidgetTip.error('The date cannot be set to be greater than the 30th when Start-month is %s.' % value)
                self.reset_combox_list([[0, 1]])
                self.pop_opts_dict('SMONTH')
                return False
        elif key == 'EMONTH':
            if 'EDAY' not in self.opts_dict:
                return True
            day = int(self.opts_dict['EDAY'])
            if int(value) == 2 and day > 28:
                WidgetTip.error('The date cannot be set to be greater than the 28th when End-month is February.')
                self.reset_combox_list([[0, 2]])
                self.pop_opts_dict('EMONTH')
                return False
            elif int(value) in [4, 6, 9, 11] and day > 30:
                WidgetTip.error('The date cannot be set to be greater than the 30th when End-month is %s.' % value)
                self.reset_combox_list([[0, 2]])
                self.pop_opts_dict('EMONTH')
                return False
        return True

    def choose_opt(self, event, cmb, x, y):
        ''' 下拉框点击事件 '''
        optname = self.get_abbre_opts(x, y)
        optval = cmb.get()
        '''根据选择的类型做出按钮的限制'''
        if optname in ['DST', 'SMODE', 'EMODE']:
            self.display_diff_mode(optname, optval)
        '''组合成脚本所需要的形式'''
        if optname == 'ZONET':
            optval = optval.replace(':', '').replace('GMT', '')
        elif optname in ['SMONTH', 'EMONTH']:
            optval = self.get_month_tup(optval)
        elif optname in ['SWSEQ', 'EWSEQ']:
            optval = self.get_weekseq_tup(optval)
        elif optname in ['SWEEK', 'EWEEK']:
            optval = self.get_week_tup(optval)
        elif optname in ['STIMEH', 'STIMEM', 'STIMES']:
            ''' 通过subcmb_list中保存的实例直接获取3个时间框的值 '''
            h = self.subcmb_list[x][1].get()
            m = self.subcmb_list[x][2].get()
            s = self.subcmb_list[x][3].get()
            if not h:h = 0
            if not m:m = 0
            if not s:s = 0
            tmpval = '%02d:%02d:%02d' % (int(h), int(m), int(s))
            optname = 'STIME'
            optval = tmpval
        elif optname in ['ETIMEH', 'ETIMEM', 'ETIMES']:
            h = self.subcmb_list[x][4].get()
            m = self.subcmb_list[x][5].get()
            s = self.subcmb_list[x][6].get()
            if not h:h = 0
            if not m:m = 0
            if not s:s = 0
            tmpval = '%02d:%02d:%02d'%(int(h), int(m), int(s))
            optname = 'ETIME'
            optval = tmpval
        ''' 一些条件判断，比如2月不能设置大于28号；4,6,9,11月不能设置31号 '''
        if self.check_limit_dependence(optname, optval):
            self.opts_dict[optname] = optval
        # InfoWindow.insert(self.options_combine())

    def display_diff_mode(self, key, val):
        """ 无夏令时 """
        disable_list = self.get_index_list()
        disable_list.remove([0, 0])
        disable_list.remove([1, 0])
        if key == 'DST':
            if val != 'NO':
                # DST为YES时，只继续开放模式和偏移
                open_list = [[2, 0], [3, 0], [4, 0]]
                disable_list = []
            else:
                # 如果之前显示器上有其他参数，清除掉
                open_list = []
                self.remove_optsdict_key(['ZONET', 'DST'], True)
        elif key == 'SMODE':
            open_list = [[0, 1], [4, 1], [4, 2], [4, 3]]
            if val == 'DATE':
                open_list.append([1, 1])
                disable_list = [[2, 1], [3, 1]]
                self.remove_optsdict_key(['SWSEQ', 'SWEEK'])
            elif val == 'WEEK':
                open_list.append([2, 1])
                open_list.append([3, 1])
                disable_list = [[1, 1]]
                self.remove_optsdict_key(['SDAY'])
            else:
                return
        elif key == 'EMODE':
            open_list = [[0, 2], [4, 4], [4, 5], [4, 6]]
            if val == 'DATE':
                open_list.append([1, 2])
                disable_list = [[2, 2], [3, 2]]
                self.remove_optsdict_key(['EWSEQ', 'EWEEK'])
            elif val == 'WEEK':
                open_list.append([2, 2])
                open_list.append([3, 2])
                disable_list = [[1, 2]]
                self.remove_optsdict_key(['EDAY'])
            else:
                return
        else:
            return
        self.reset_combox_list(open_list)
        self.disable_combox_list(disable_list)

    def remove_optsdict_key(self, inlist, reverse=False):
        '''
        reverse=True时，删除opts_dict中除去inlist之外的键值
        否则删除inlist
        '''
        if not inlist:
            return
        rmlist = inlist
        if reverse:
            tmp_list = []
            for i in self.opts_dict:
                if i not in inlist:
                    tmp_list.append(i)
            rmlist = tmp_list
        for i in rmlist:
            if i in self.opts_dict:
                self.opts_dict.pop(i)

    def pop_opts_dict(self, which):
        if which in self.opts_dict:
            self.opts_dict.pop(which)

    def options_combine(self):
        opts_str = ""
        for k,v in sorted(self.opts_dict.items()):
            if not len(opts_str):
                opts_str = "%s=%s" % (k, v)
            else:
                opts_str = "%s=%s," % (k, v) + opts_str
        return opts_str

    def init_display(self):
        """ 初始化combox显示 """
        disable_list = self.get_index_list()
        disable_list.remove([0, 0])
        disable_list.remove([1, 0])
        self.disable_combox_list(disable_list)

    def onoff_label_view(self, tp, x, y):
        lab_y = y
        if x == self.row-1:
            if y in [1, 2, 3]:
                lab_y = 1
            elif y in [4, 5, 6]:
                lab_y = 2
        color = 'Gray' if tp == 'OFF' else 'black'
        self.label_list[x][lab_y]['fg'] = color

    def disable_combox_list(self, inlist):
        for x, y in inlist:
            self.onoff_label_view('OFF', x, y)
            self.subcmb_list[x][y].set('')
            self.subcmb_list[x][y]['state'] = 'disabled'

    def reset_combox_list(self, inlist):
        for x, y in inlist:
            self.onoff_label_view('ON', x, y)
            self.subcmb_list[x][y].set('')
            self.subcmb_list[x][y]['state'] = 'readonly'

    def set_combox_value(self, x, y, index):
        self.onoff_label_view('ON', x, y)
        self.subcmb_list[x][y].current(index)
        self.subcmb_list[x][y]['state'] = 'readonly'


